package com.demo.uitls;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;

/**
 * @Author DongXL
 * @Create 2017-09-15 15:16
 */
public enum UrlSignUtils {

    INSTANCE;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    /**
     * 返回带签名的URL
     *
     * @param originUrl
     * @param secret
     * @return
     */
    public String signUrl(String originUrl, String secret) {
        String sign = sign(originUrl, secret);
        return String.format("%s&sign=%s", originUrl, sign);
    }

    /**
     * 返回签名
     *
     * @param originUrl
     * @param secret
     * @return
     */
    public String sign(String originUrl, String secret) {
        Map<String, String> queryParamMap = getQueryParamMap(originUrl);
        if (MapUtils.isEmpty(queryParamMap)) {
            logger.warn("请求的url不正确，请检查，url：{}", originUrl);
            return null;
        }
        return sign(queryParamMap, secret);
    }

    /**
     * 返回签名
     *
     * @param o
     * @param secret
     * @return
     */
    public String sign(Object o, String secret) {
        Map<String, String> map = null;
        try {
            map = BeanUtils.describe(o);
        } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) {
            e.printStackTrace();
        }
        if (MapUtils.isNotEmpty(map)) {
            for (String key : Arrays.asList("sign", "class")) {
                map.remove(key);
            }
        }
        if (MapUtils.isEmpty(map)) {
            return null;
        }
        return sign(map, secret);
    }

    /**
     * 返回签名
     *
     * @param map
     * @param secret
     * @return
     */
    public String sign(Map<String, String> map, String secret) {
        Set<String> sortedKeySet = getSortedKeySet(map);
        String signString = getSignString(map, sortedKeySet, secret);
        return sign(signString);
    }

    private Map<String, String> getQueryParamMap(String urlStr) {
        try {
            URL url = new URL(urlStr);
            String queryStr = url.getQuery();
            String[] kvArrays = StringUtils.split(queryStr, "&");
            Map<String, String> map = new HashMap<>();
            for (String kv : kvArrays) {
                String[] args = StringUtils.split(kv, "=");
                String k = args[0];
                String v = args[1];
                if ("sign".equals(k)) {
                    continue;
                }
                map.put(k, v);
            }
            return map;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 加密
     *
     * @param str
     * @return
     */
    private String sign(String str) {
        return DigestUtils.md5Hex(str);
    }

    /**
     * map的key降序排列，返回keySet
     *
     * @param map
     * @return
     */
    private Set<String> getSortedKeySet(Map<String, String> map) {
        TreeMap sortedMap = new TreeMap(map);
        return sortedMap.descendingKeySet();
    }

    /**
     * 待加密字符串
     *
     * @param map
     * @param sortedKeySet
     * @param secret
     * @return
     */
    private String getSignString(Map<String, String> map, Set<String> sortedKeySet, String secret) {
        List<String> sortedParamList = new ArrayList<>();
        for (String key : sortedKeySet) {
            String value = map.getOrDefault(key, "");
            sortedParamList.add(key + "=" + value);
        }
        sortedParamList.add("key=" + secret);
        return StringUtils.join(sortedParamList, "&");
    }

}
